// 静态属性
// 在课程二的ES6部分1我们成学到什么时静态属性：这些属性存在于类本身上面而不是类的实例上，
// 我们只能通过类.属性名称的方式来调用，而不是在实例上进行调用
class Grid{
    static origin = {x:0,y:0};
    calculateDuataceFromOrigin(point:{x:number;y:number}){
        // console.log(point);
        let xDist = (point.x - Grid.origin.y);
        let yDist = (point.y - Grid.origin.y);
        return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
    }
    constructor(public scale:number){
        // console.log(scale);
    }
    
}
// 1x scale
let grid1 = new Grid(1.0);
// 5x scale
let grid2 = new Grid(5.0);

// console.log(grid1.calculateDuataceFromOrigin({x:1,y:11}));
// console.log(grid2.calculateDuataceFromOrigin({x:5,y:55}));

// 如果代码中标注处写了this.origin的话是会直接报错的，因为构造函数生成的实例，
// 而实例是不会继承类的静态方法



// 抽象类
// 抽象类作为其他派生类的基类使用
// 它们一般不会直接被实例化
// 不同于接口，抽象类可以包含成员的实现细节
// abstract关键字是用于定义抽象类和在抽象类内部定义抽象方法

// 抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
// 抽象方法的语法与接口方法相似
// 两者都是定义方法签名但不包含方法体
// 然而抽象方法必须包含abstruse关键字

abstract class Department {
    // 相当于定义了一个公共接口name进行赋值
    constructor(public name:string) {}
    printName():void{
        console.log('Department name:'+this.name);
    }
    // 必须在派生类中实现
    abstract printMeeting():void;
    // abstract hello():void;
}
class AccountingDepartment extends Department{
    constructor(){
        // 在派生类构造函数中必须调用super()
        super('Accounting and Auditing');
    }
    printMeeting():void{
        console.log('The Accounting Department meets each Monday at 10am');   
    }
    hello():void{
        // 这个方法不会被继承下去 抽象类与解耦类似， 
        // 因为抽象类中没有定义该名称方法，改成其他名字也是一样
        console.log('你好！世界！');
    }
}
// 允许创建一个对抽象类型的引用
let department:Department;
// 错误: 不能创建一个抽象类的实例
// department = new Department();
// 允许对一个抽象子类进行实例化和赋值
department = new AccountingDepartment();
console.log(department);
// 继承自父类 输出Department name: Accounting and Auding
department.printName();
// 子类自身自带方法 输出The Accounting Department meets each Monday at 10am.
department.printMeeting();
// 错误：方法在上声明的抽象类中不存在
// department.hello();


// 高级技巧
// 把类当作接口使用
// 因为类可以创建出类型
// 所以你能够在允许使用接口的地方使用类
class Point2{
    x:number;
    y:number;
}
interface point3d extends Point2{
    z:number;
}
let point3d:point3d={x:1,y:2,z:3}
console.log(point3d);

// 当我们在TypeScript里声明了一个类的时候，
// 实际上声明了许多东西

// 首先就是声明类的实例的类型
class Greeter {
    greeting:string;
    constructor(message:string){
        this.greeting = message;
    }
    greet(){
        return "Hello," + this.greeting;
    }
}
// 声明变量greeter的类型为Greeter
let greeter:Greeter;
// 创建一个Greeter的实例
greeter = new Greeter("world");
console.log(greeter.greet());


// 实例部分和惊静态部分是分开的
class Greeter2{
    static standarGreeting = "Hello,there";
    greeting:string;
    greet(){
        if(this.greeting){
            return "Hello,"+this.greeting;
        }else{
            return Greeter.standarGreeting;
        }
    }
}
let greeter1:Greeter2;
greeter1 = new Greeter();
// hello there
console.log(greeter1.greet());

let greeter2Maker:typeof Greeter2 = Greeter2;
// 这里的typeof Greeter的语法意思是取Greeter类的类型，而不是实例的类型
greeter2Maker.standarGreeting = "Hey there";

let greeter2:Greeter = new greeter2Maker();
// Hey there
console.log(greeter2.greet());
